package elicecn.web.struts2ext.dao;

import java.io.Serializable;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;
import org.springframework.util.ClassUtils;

import elicecn.web.struts2ext.dto.BaseDto;
import elicecn.web.struts2ext.dto.Pagination;
import elicecn.web.struts2ext.model.BaseModel;
import elicecn.web.struts2ext.util.BeanUtils;

public abstract class BaseDaoImpl<T extends BaseModel, PK extends Serializable, DTO extends BaseDto>
		extends SqlMapClientDaoSupport implements BaseDao<T, PK, DTO> {
	private Class<T> persistentClass;

	public BaseDaoImpl(final Class<T> persistentClass) {
		this.persistentClass = persistentClass;
	}

	@SuppressWarnings("unchecked")
	public T get(PK id) {
		T object = (T) getSqlMapClientTemplate().queryForObject(
				IBatisDaoUtils.getObjectQuery(ClassUtils
						.getShortName(this.persistentClass)), id);
		if (object == null) {
			throw new RuntimeException("Get Model Error");
		}
		return object;
	}

	/**
	 * {@inheritDoc}
	 */
	public T save(final T object) {
		String className = ClassUtils.getShortName(object.getClass());
		Object primaryKey = IBatisDaoUtils.getPKValue(object);

		String keyId = null;
		if (primaryKey != null && ((Long) primaryKey).longValue() != 0L) {
			keyId = primaryKey.toString();
		}

		if (StringUtils.isBlank(keyId)) {
			primaryKey = getSqlMapClientTemplate().insert(
					IBatisDaoUtils.getInsertQuery(className), object);
			IBatisDaoUtils.setPrimaryKey(object, primaryKey);
		} else {
			int updatedNum = getSqlMapClientTemplate().update(
					IBatisDaoUtils.getUpdateQuery(className), object);
			if (updatedNum == 0) {
				throw new RuntimeException("Update Error");
			}
		}
		if (IBatisDaoUtils.getPKValue(object) == null) {
			throw new RuntimeException("Insert or Update Error");
		} else {
			return object;
		}
	}

	public void updateSelective(T object) {
		String className = ClassUtils.getShortName(object.getClass());
		Object primaryKey = IBatisDaoUtils.getPKValue(object);

		if (primaryKey != null && ((Long) primaryKey).longValue() != 0L) {
			getSqlMapClientTemplate().update(
					IBatisDaoUtils.getUpdateSelectiveQuery(className), object);
		} else {
			throw new RuntimeException("Update Selective Error");
		}
	}

	public void remove(PK id) {
		getSqlMapClientTemplate().update(
				IBatisDaoUtils.getRemoveQuery(ClassUtils
						.getShortName(this.persistentClass)), id);
	}

	public Pagination findObjectsWithPg(BaseDto dto) {
		return findObjectsWithPg(IBatisDaoUtils.getPaginationQuery(ClassUtils
				.getShortName(this.persistentClass)), dto);
	}

	@SuppressWarnings("unchecked")
	public Pagination findObjectsWithPg(String statementName, BaseDto dto) {
		Pagination pg = new Pagination();

		// dto.setNeedCount(true);
		Object count = getSqlMapClientTemplate().queryForObject(
				IBatisDaoUtils.getCountQuery(statementName), dto);
		int totalCount = Integer.parseInt(count.toString());

		dto.setTotalCount(totalCount);
		dto.calcStart();
		// dto.setNeedCount(false);
		List resultList = getSqlMapClientTemplate().queryForList(statementName,
				dto);

		BeanUtils.copyProperties(pg, dto);
		pg.setTotalCount(totalCount);
		pg.setResultList(resultList);

		return pg;
	}

}
